import hashlib

class VirtIO:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(VirtIO, cls).__new__(cls)
        return cls._instance

    def __init__(self):
        self.consoles = {}

    def create(self, key=None):
        console = VirtIOConsole(key)
        self.consoles[console.id] = console
        return console

    def get_console(self, console_id):
        return self.consoles.get(console_id, None)

class VirtIOConsole:
    def __init__(self, key=None):
        self.id = id(self)
        self.key = key
        self.output_buffer = []
        self.input_calls = []

    def export(self, locals_dict=globals()):
        self.locals_dict = locals_dict
        self.locals_dict['print'] = self.custom_print
        self.locals_dict['input'] = self.custom_input

    def detach(self):
        if 'print' in self.locals_dict:
            del self.locals_dict['print']
        if 'input' in self.locals_dict:
            del self.locals_dict['input']

    def delete(self):
        self.detach()
        del VirtIO._instance.consoles[self.id]

    def custom_print(self, *args, **kwargs):
        value = ' '.join(map(str, args))
        if self.key:
            value = self._encrypt(value)
        self.output_buffer.append(value)
        if len(self.output_buffer) > 128:
            self.output_buffer.pop(0)

    def custom_input(self, prompt=None):
        input_call = []
        self.input_calls.append(input_call)
        if prompt:
            self.custom_print(prompt, end='')
        return input_call

    def input_proxy(self, value):
        if self.input_calls:
            self.input_calls.pop(0).append(value)

    def buffer(self):
        return self.output_buffer

    def _encrypt(self, data):
        key = hashlib.sha256(str(self.key).encode()).digest()
        encrypted = b''
        for i in range(len(data)):
            encrypted += bytes([data[i] ^ key[i % len(key)]])
        return encrypted

    def _decrypt(self, data):
        key = hashlib.sha256(str(self.key).encode()).digest()
        decrypted = b''
        for i in range(len(data)):
            decrypted += bytes([data[i] ^ key[i % len(key)]])
        return decrypted.decode()
